﻿using System;
using System.Collections;
using Microsoft.Practices.Unity;
using Tp.Interfaces;

namespace Tp.ViewModelLocator
{
    public class UnityServiceLocator : IUnityServiceLocator
    {
        /// <summary>
        /// the unity container.
        /// </summary>
        private readonly UnityContainer _unityContainer;

        public UnityServiceLocator()
        {
            this._unityContainer = new UnityContainer();
        }

        /// <summary>
        /// Gets this instance.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <returns>The retrieved object.</returns>
        public T Get<T>()
        {
            return this._unityContainer.Resolve<T>();
        }

        /// <summary>
        /// Gets the specified type.
        /// </summary>
        /// <param name="type">The requested type.</param>
        /// <returns>The retrieved object.</returns>
        public Type Get(Type type)
        {
            return (Type)this._unityContainer.Resolve(type);
        }

        /// <summary>
        /// Get's all.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <returns>The retrieved object.</returns>
        public IEnumerable GetAll<T>()
        {
            return this._unityContainer.ResolveAll<T>();
        }

        /// <summary>
        /// Gets the specified key.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <param name="key">The requested key.</param>
        /// <returns>The retrieved object.</returns>
        public T Get<T>(string key)
        {
            return this._unityContainer.Resolve<T>(key);
        }

        /// <summary>
        /// Injects the specified instance.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <param name="instance">The requested instance.</param>
        public void Inject<T>(T instance)
        {
            this._unityContainer.RegisterInstance(instance, new ExternallyControlledLifetimeManager());
        }

        /// <summary>
        /// Injects as singleton.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <param name="instance">The requested instance.</param>
        public void InjectAsSingleton<T>(T instance)
        {
            this._unityContainer.RegisterInstance(instance);
        }

        /// <summary>
        /// Registers this instance.
        /// </summary>
        /// <typeparam name="TInterface">The type of the interface.</typeparam>
        /// <typeparam name="TImplementor">The type of the implementor.</typeparam>
        public void Register<TInterface, TImplementor>() where TImplementor : TInterface
        {
            this._unityContainer.RegisterType<TInterface, TImplementor>();
        }

        /// <summary>
        /// Registers the specified key.
        /// </summary>
        /// <typeparam name="TInterface">The type of the interface.</typeparam>
        /// <typeparam name="TImplementor">The type of the implementor.</typeparam>
        /// <param name="key">The requested key.</param>
        public void Register<TInterface, TImplementor>(string key) where TImplementor : TInterface
        {
            this._unityContainer.RegisterType<TInterface, TImplementor>(key);            
        }

        /// <summary>
        /// Registers as singleton.
        /// </summary>
        /// <typeparam name="TInterface">The type of the interface.</typeparam>
        /// <typeparam name="TImplementor">The type of the implementor.</typeparam>
        public void RegisterAsSingleton<TInterface, TImplementor>() where TImplementor : TInterface
        {
            this._unityContainer.RegisterType<TInterface, TImplementor>(new ContainerControlledLifetimeManager());
        }
    }
}
